import ArgumentParser
import Foundation
import PBXProj

extension Generator {
    struct Arguments: ParsableArguments {
        @Argument(
            help: """
Path to the directory where `.xcscheme` files should be written.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: true) }
        )
        var outputDirectory: URL

        @Argument(
            help: """
Path to where the `xcschememanagement.plist` file should be written.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var schemeManagementOutputPath: URL

        @Argument(
            help: """
Specifies how schemes are automatically generated:

- `auto`: If no custom schemes are specified, a scheme will be created for \
every buildable target. If custom schemes are provided, no autogenerated \
schemes will be created.
- `all`: A scheme is generated for every buildable target even if custom \
schemes are provided.
- `none`: No schemes are automatically generated.
"""
        )
        var autogenerationMode: AutogenerationMode

        @Argument(help: "Name of the default Xcode configuration.")
        var defaultXcodeConfiguration: String

        @Argument(help: "Absolute path to the Bazel workspace.")
        var workspace: String

        @Argument(help: """
Bazel workspace relative path to where the final `.xcodeproj` will be output.
""")
        var installPath: String

        @Argument(
            help: """
Path to a file that contains a JSON representation of \
`[TargetID: ExtensionPointIdentifier]`.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var extensionPointIdentifiersFile: URL

        @Argument(
            help: """
Path to a file containing arguments for custom execution actions.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var executionActionsFile: URL

        @Argument(
            help: """
Path to a file containing arguments for target-level command-line arguments \
and environment variables.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var targetsArgsEnvFile: URL

        @Argument(
            help: """
Path to a file that contains arguments for custom schemes.
""",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var customSchemesFile: URL

        @Argument(
            help: """
Path to a file containing `[TargetID: [TargetID]]`, which maps a target to a \
list of addition targets to include for Xcode Preview support.
""",
            transform: { path in
                guard !path.isEmpty else {
                    return nil
                }
                return URL(fileURLWithPath: path, isDirectory: false)
            }
        )
        var transitivePreviewTargetsFile: URL?

        @Option(
            parsing: .upToNextOption,
            help: "Path to the consolidation maps.",
            transform: { URL(fileURLWithPath: $0, isDirectory: false) }
        )
        var consolidationMaps: [URL]

        @Option(
            parsing: .upToNextOption,
            help: "Pairs of <target> <extension-host> target IDs."
        )
        private var targetAndExtensionHosts: [TargetID] = []

        mutating func validate() throws {
            guard targetAndExtensionHosts.count.isMultiple(of: 2) else {
                throw ValidationError("""
<target-and-extension-hosts> (\(targetAndExtensionHosts.count) elements) must \
be <target> and <extension-hosts> pairs.
""")
            }
        }
    }
}

extension Generator.Arguments {
    func calculateExtensionHostIDs() -> [TargetID: [TargetID]] {
        var ret: [TargetID: [TargetID]] = [:]
        for index in stride(
            from: 0,
            to: targetAndExtensionHosts.count - 1,
            by: 2
        ) {
            ret[targetAndExtensionHosts[index], default: []]
                .append(targetAndExtensionHosts[index+1])
        }
        return ret
    }
}
